#include <iostream>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "error.hpp"
#include <functional>

namespace Udp_Server
{
    const static uint16_t default_port = 8080;
    using func_t =  std::function<std::string(std::string)>;
    class UdpServer
    {
    public:
        UdpServer(func_t cb,uint16_t port = default_port)
        :port_(port),
        service_(cb)
        {
           std::cout << port_ <<std::endl;
        }
        void init_server()
        {
            //1. 创建套接字接口，打开网络文件
            sock_ = socket(AF_INET,SOCK_DGRAM,0);
            if(sock_ <0)
            {
                std::cerr <<  "create socket error" << strerror(errno) << std::endl;
                exit(SOCKET_ERR);
            }
            std::cout << "create socket error " << sock_<< std::endl;

            //2. 给服务器指明ip地址和端口号
            struct sockaddr_in local;
            bzero(&local,sizeof(local));

            //需要将主机序列转换成网络序列
            local.sin_family = AF_INET;
            local.sin_port = htons(port_);
            //云服务器，或者一款服务器，一般不要指明某一个确定的ip
            local.sin_addr.s_addr = INADDR_ANY;//让我们的udpserver启动时绑定本主机上的任意ip

           if(bind(sock_,(struct sockaddr*)&local,sizeof(local)) < 0)
           {
                std::cerr << "bind socket error: "<< strerror(errno) <<std::endl;
                exit(BIND_ERR);
           }
           std::cout << "bind socket sucess " <<sock_ << std::endl;
        }
        void start()
        {
            char buffer[1024] = {0};
            while(1)
            {
                //收
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                int n = recvfrom(sock_,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
                if(n >0) buffer[n] = '\0';
                else continue;

                //提取客服端信息
                std::string client_ip = inet_ntoa(peer.sin_addr);
                uint16_t client_port = ntohs(peer.sin_port);

                std::cout << "clientip-" << client_ip <<"-"<<  "clientport-" << client_port <<"#" <<buffer <<std::endl; 

                //业务处理
                std::string response = service_(buffer);
                //发
                sendto(sock_,response.c_str(),response.size(),0,(struct sockaddr*)&peer,sizeof(peer));
            }
        }
        ~UdpServer()
        {
            ;
        }
    private:
        int sock_;
        uint16_t port_;
        func_t service_;
    };
}